import filecmp
import os
import shutil
import stat

############################################################################
#Event 
EVENT_CREATE_DIR		= 1
EVENT_CREATE_FILE		= 2
EVENT_OVERWRITE_FILE	= 3

class Event:
	def __init__(self, type, src, dst):
		self.type	= type
		self.src	= src
		self.dst	= dst
		self.skip	= False

############################################################################
def update(src, dst):
	'''
	src should be a file or directory, and should exist
	dst should also be a path, may exist or not exist
	'''
    # assert isinstance(src, str), 'src should be a string'
    # assert isinstance(dst, str), 'dst should be a string'

	if not os.path.exists(src):
		raise ValueError('Can not find src= %s'%(src))

	# if src is a directory
	if os.path.isdir(src):
		if not os.path.exists(dst):
			event	= Event(EVENT_CREATE_DIR, src, dst)
			yield event
			if not event.skip:
				os.makedirs(dst)

		if os.path.exists(dst):
			for name in os.listdir(src):
				srcpath	= os.path.join(src, name)
				dstpath	= os.path.join(dst, name)
				# foward all yields
				for x in update(srcpath, dstpath):
					yield x

	# if src is a file
	elif os.path.isfile(src):
		# if dst exists and they are not the same
		if os.path.exists(dst):
			assert os.path.isfile(dst), 'dst:%s should be a file'%(dst)
			if not filecmp.cmp(src, dst):
				event	= Event(EVENT_OVERWRITE_FILE, src, dst)
				yield event
				if not event.skip:
					os.chmod(dst, stat.S_IWRITE)
					shutil.copy2(src, dst)
		# dst does not exist
		else:
			event	= Event(EVENT_CREATE_FILE, src, dst)
			yield event
			if not event.skip:
				# to make sure directory of dst exists
				dirpath	= os.path.dirname(dst)
				if not os.path.exists(dirpath):
					os.makedirs(dirpath)
				# copy file
				shutil.copy2(src, dst)
	else:
		assert False, 'should be dir or file'
	
############################################################################
def overwrite(src, dst):
	'''
	src should be a file or directory, and should exist
	dst should also be a path, may exist or not exist
	'''
    # assert isinstance(src, str), 'src should be a string'
    # assert isinstance(dst, str), 'dst should be a string'

	if not os.path.exists(src):
		raise ValueError('Can not find src= %s'%(src))

	# if src is a directory
	if os.path.isdir(src):
		if not os.path.exists(dst):
			os.makedirs(dst)

		assert os.path.exists(dst)
		for name in os.listdir(src):
			srcpath	= os.path.join(src, name)
			dstpath	= os.path.join(dst, name)

			overwrite(srcpath, dstpath)

	# if src is a file
	elif os.path.isfile(src):
		# if dst exists and they are not the same
		if os.path.exists(dst):
			assert os.path.isfile(dst), 'dst:%s should be a file'%(dst)
			if not filecmp.cmp(src, dst):
				os.chmod(dst, stat.S_IWRITE)
				shutil.copy2(src, dst)

		# dst does not exist
		else:
			# to make sure directory of dst exists
			dirpath	= os.path.dirname(dst)
			if not os.path.exists(dirpath):
				os.makedirs(dirpath)
			# copy file
			shutil.copy2(src, dst)
	else:
		assert False, 'should be dir or file'

############################################################################
if __name__ == '__main__':
	src		= r'c:\Python31'
	dst		= r'c:\abc'
	for event in update(src, dst):
		print(event.type, event.src, event.dst)
